package top.ochiamalu.aioj.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.StopWatch;
import top.ochiamalu.aioj.common.ErrorCode;
import top.ochiamalu.aioj.domain.bo.ExecuteMessage;
import top.ochiamalu.aioj.domain.entity.TestCase;
import top.ochiamalu.aioj.exception.BusinessException;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.List;

import static top.ochiamalu.aioj.constant.JudgeConstants.MEMORY_USAGE_INFO_OFFSET;

/**
 * 进程工具类
 *
 * @author ochiamalu
 * @date 2025/01/24
 */
@Slf4j
public final class ProcessUtils {
    private ProcessUtils() {
        throw new IllegalStateException("Utility class");
    }

    /**
     * 获取编译代码消息
     *
     * @param runProcess 运行过程
     * @return {@link ExecuteMessage }
     */
    public static ExecuteMessage getCompileCodeMessage(Process runProcess) {
        ExecuteMessage executeMessage = new ExecuteMessage();

        try {
            StopWatch stopWatch = new StopWatch();
            stopWatch.start();
            // 等待程序执行，获取错误码
            int exitValue = runProcess.waitFor();
            executeMessage.setExitValue(exitValue);
            // 正常退出
            // 分批获取进程的正常输出
            BufferedReader bufferedReader = new BufferedReader(
                    new InputStreamReader(runProcess.getInputStream(), getCharset())
            );
            List<String> outputStrList = new ArrayList<>();
            // 逐行读取
            String outputLine;
            while ((outputLine = bufferedReader.readLine()) != null) {
                outputStrList.add(outputLine);
            }
            if (exitValue == 0) {
                // 正常退出
                log.info("编译成功");
            } else {
                // 异常退出
                log.error("编译失败，错误码： {}", exitValue);
                log.error("错误信息：{}", StringUtils.join(outputStrList, "\n"));
                String errorMessage = StringUtils.join(outputStrList, "\n");
                executeMessage.setMessage(errorMessage);
            }
            stopWatch.stop();
            log.info("编译执行时间：{}ms", stopWatch.getLastTaskTimeMillis());
            executeMessage.setTime(stopWatch.getLastTaskTimeMillis());
        } catch (Exception e) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "获取信息失败");
        }
        return executeMessage;
    }

    /**
     * 运行程序
     *
     * @param runProcess 运行过程
     * @param testCase   测试用例信息
     * @return {@link ExecuteMessage }
     */
    public static ExecuteMessage runProgram(Process runProcess, TestCase testCase) {
        ExecuteMessage executeMessage = new ExecuteMessage();

        String args = testCase.getInput();
        //TODO 超时控制
        try {
            OutputStream outputStream = runProcess.getOutputStream();
            OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
            InputStream inputStream = runProcess.getInputStream();
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, getCharset()));
            // 获取进程ID
//            long pid = runProcess.pid();

            // 获取内存使用
//            Long memoryUsage = getMemoryUsage(pid);
            executeMessage.setMemory(0L);

            StopWatch stopWatch = new StopWatch();
            stopWatch.start();

            // 验证和清理输入
            if (args != null && !args.trim().isEmpty()) {
                // 向控制台输入程序
                String[] s = args.trim().split("\\s+");
                String join = String.join("\n", s) + "\n";
                outputStreamWriter.write(join);
                outputStreamWriter.flush();

            }
            //TODO timeout
            int exitValue = runProcess.waitFor();

            // 分批获取进程输出
            StringBuilder outputStringBuilder = new StringBuilder();
            String outputLine;
            while ((outputLine = bufferedReader.readLine()) != null) {
                outputStringBuilder.append(outputLine);
            }

            stopWatch.stop();
            executeMessage.setTime(stopWatch.getLastTaskTimeMillis());
            executeMessage.setMessage(outputStringBuilder.toString());
            executeMessage.setExitValue(exitValue);

            outputStream.close();
            bufferedReader.close();
            outputStreamWriter.close();
            inputStream.close();
        } catch (Exception e) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "程序执行失败");
        } finally {
            // 确保进程在所有资源关闭后销毁
            runProcess.destroy();
        }
        return executeMessage;
    }

    /**
     * 获取内存使用情况
     *
     * @param pid pid
     * @return {@link Long }
     * @throws IOException IOException
     */
    public static Long getMemoryUsage(long pid) throws IOException {
        //TODO 非win系统实现
        ProcessBuilder builder = new ProcessBuilder("cmd.exe", "/c", "tasklist /FI \"PID eq " + pid + "\"");
        Process p = builder.start();
        // 使用task-list命令获取内存信息
        BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream(), getCharset()));
        String line;
        while ((line = reader.readLine()) != null) {
            if (line.contains("K")) {
                int index = line.indexOf("K");
                String trimmedStr = line.substring(index - MEMORY_USAGE_INFO_OFFSET, index).trim();
                return Long.valueOf(trimmedStr.replace(",", ""));

            }
        }
        return 0L;
    }

    /**
     * 获取字符集
     *
     * @return {@link String }
     */
    private static String getCharset() {
        return "UTF-8";
    }
}
